package com.shockweb.rpc.spring;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;
import java.util.List;

import com.shockweb.common.context.ContextManager;
import com.shockweb.bridge.ServiceRequest;
import com.shockweb.bridge.ServiceResult;
import com.shockweb.rpc.RpcManager;

import java.lang.reflect.InvocationHandler;

/**
 * 接口代理
 * @see InvocationHandler
 * 
 * @author 彭明华
 * 2018年1月26日 创建
 */
public class InterfaceProxy implements InvocationHandler{	

	/**
	 * 微服务命名空间
	 */
	private String spaceName;

	/**
	 * 注册服务中心
	 */
	private String registerCenter;
	
	/**
	 * 微服务名称
	 */
	private String service;
	
	/**
	 * 是否同步上下文
	 */
	private boolean context = true;
	
	/**
	 * 是否广播方式调用服务
	 */
	private boolean broadcast = false;
	
	/**
	 * 是否异步执行
	 */
	private boolean asynchronous = false;

	/**
	 * 构造方法
	 * @param registerCenter
	 * @param spaceName
	 * @param service
	 * @param context
	 * @param broadcast
	 * @param asynchronous
	 */
	public InterfaceProxy(String registerCenter,String spaceName,String service, boolean context,boolean broadcast,boolean asynchronous){
		this.registerCenter = registerCenter;
		this.spaceName = spaceName;
		this.service = service;
		this.context = context;
		this.broadcast = broadcast;
		this.asynchronous = asynchronous;
	}
	
	/**
	 * @see InvocationHandler#invoke(Object, Method, Object[])
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		InvocationHandler hander = Proxy.getInvocationHandler(proxy);
		if(hander instanceof InterfaceProxy){
			ServiceRequest request = new ServiceRequest();
			request.setSpaceName(spaceName);
			request.setService(service);
			request.setMethod(method.getName());
			request.setParameterTypes(method.getParameterTypes());
			request.setParams(args);
			if(context){
				//有上下文
				request.setContext(ContextManager.getContextParam());
			}
			ServiceResult result = null;
			if(registerCenter==null || registerCenter.equals("") || registerCenter.trim().equals("")){
				if(broadcast){
					List<Object> rtn = null;
					if(asynchronous) {
						rtn = RpcManager.getClientManager().asyncRpcAllService(request);
					}else {
						rtn = RpcManager.getClientManager().rpcAllService(request);
					}
					if(rtn!=null && !rtn.isEmpty()) {
						if(rtn.get(0) == null) {
							return null;
						}else if(rtn.get(0) instanceof ServiceResult) {
							result = (ServiceResult)rtn.get(0); 
						}else {
							throw (Exception)rtn.get(0);
						}
					}else {
						return null;
					}
				}else{
					if(asynchronous) {
						RpcManager.getClientManager().asyncRpcService(request);
					}else {
						result = RpcManager.getClientManager().rpcService(request);
					}
				}
			}else{
				if(broadcast){
					List<Object> rtn = null;
					if(asynchronous) {
						rtn = RpcManager.getClientManager(registerCenter).asyncRpcAllService(request);
					}else {
						rtn = RpcManager.getClientManager(registerCenter).rpcAllService(request);
					}
					if(rtn!=null && !rtn.isEmpty()) {
						if(rtn.get(0) == null) {
							return null;
						}else if(rtn.get(0) instanceof ServiceResult) {
							result = (ServiceResult)rtn.get(0); 
						}else {
							throw (Exception)rtn.get(0);
						}
					}else {
						return null;
					}
				}else{
					if(asynchronous) {
						RpcManager.getClientManager(registerCenter).asyncRpcService(request);
					}else {
						result = RpcManager.getClientManager(registerCenter).rpcService(request);
					}
					
				}
			}
			if(context && result.getContextParam()!=null){
				//同步回上下文
				ContextManager.putAll(result.getContextParam());
			}
			if(result!=null){
				return result.getResult();
			}else {
				return null;
			}
			
		}else{
			return method.invoke(proxy, args);
		}
	}
	
	/**
	 * 创建innerInterface的实例
	 * @param innerInterface
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T newInstance(Class<T> innerInterface) {
		ShockWebRemote shockWebRemote = innerInterface.getAnnotation(ShockWebRemote.class);
		return (T) Proxy.newProxyInstance(innerInterface.getClassLoader(), new Class[]{innerInterface}, 
				new InterfaceProxy(shockWebRemote.registerCenter(),shockWebRemote.spaceName(),
						shockWebRemote.value(),shockWebRemote.context(),shockWebRemote.broadcast(),shockWebRemote.asynchronous()));
	}
	

}

